#ifndef EQUATIONSOLVER_H
#define EQUATIONSOLVER_H

#include <iostream>
#include <cmath>

using namespace std;

class Function{
 public:
  virtual double operator()(double _x){
    return 0;
  }
  virtual double diff(double _x){
    return 0;
  }
};



class EquationSolver{
 public:
  virtual double solve()=0;
};

Function func;

class Bisection : public EquationSolver{
 private:
  double a,b,delta,eps;
  int M;
  Function &f;
 public:
 Bisection():f(func){}//initialize function
 Bisection(Function &_f, double _a, double _b, double _delta, double _eps, int _M):f(_f){
    a = _a; b = _b; delta = _delta; eps = _eps; M = _M;//赋值
  }
  double solve(){
    double h = b-a, u = f(a), c = 0, w = 0;
    for (int k = 0; k <= M; k++){
      h = h/2;
      c = a+h;
      w = f(c);
      if(fabs(h) < delta || fabs(w) < eps)
	break;
      else if ((w<0 && u<0) || (w>0 && u>0))
	a = c;
    }
    return c;
  }

  
};

class Newton :  EquationSolver{
 private:
  double x0,eps;
  int M;
  Function &f;
 public:
 Newton():f(func){}
 Newton(Function &_f, double _x0, double _eps, int _M):f(_f){
    x0 = _x0; eps = _eps; M = _M;
  }
  double solve(){
    double u;
    for(int k = 0; k <= M; k++){
      u = f(x0);
      if(fabs(u) < eps)
	break;
      x0 = x0 - u / f.diff(x0);
    }
    return x0;
  }
};

class Secant : public EquationSolver{
 private:
  double x0, x1, delta, eps;
  int M;
  Function &f;
 public:
 Secant():f(func){}
 Secant(Function &_f, double _x0, double _x1, double _delta, double _eps, int _M):f(_f){
    x0 = _x0;
    x1 = _x1;
    delta = _delta;
    eps = _eps;
    M = _M;
  }

  double solve(){
    double u = f(x1);
    double v = f(x0);
    for (int k = 2; k <= M;k++){
      if(fabs(u) > fabs(v)){
	swap(x1,x0);
	swap(u,v);
      }
      double s = (x1-x0)/(u-v);
      x0 = x1;
      v = u;
      x1 = x1-u*s;
      u = f(x1);
      if(fabs(x1-x0) < delta || fabs(u) < eps)
	break;
    }
    return x1;
  }
};

#endif
